//触发更新视图

function updatedView() {
    console.log("视图更新")
}

//监听定义数组原型
const oldArrayProperty = Array.prototype
//创建新对象，原型指向oldArrayProperty，再扩展新的方法不会影响新的原型；
const arrProto = Object.create(oldArrayProperty);
// arrProto.push = function(){

// }
// arrProto.pop = function(){

// }

['push','pop','shift','unshift','splice'].forEach(methodName =>{
    arrProto[methodName] = function(){
        updatedView() //触发视图更新

        oldArrayProperty[methodName].call(this,...arguments)
    }
})



//重新定义属性，监听起来

function defineReactive(target,key,value){
    //深度监听
    observer(value)
    
    
    //核心Api

    Object.defineProperty(target,key,{
        get(){
            return value
        },
        set(newValue){
            if(newValue !== value){
                //设置新值
                    //也需要深度监听
                    observer(newValue)

                //注意，value  一直在闭包中，此处设置完之后，再get 时也是
                value = newValue

                //触发更新视图
                updatedView()
            }
        }
    })
}

//监听对象属性
function observer(target){
    if(typeof target !== 'object' || target === null){
        //不是对象或数组
        return target
    }
    if(Array.isArray(target)){
        target.__proto__ = arrProto
    }
    //重新定义各个属性（for in 也可以遍历数组）
    for(let key in target) {
        //console.log(key)
        defineReactive(target,key,target[key])
    }
}

//准备数据
const data = {
    name:"zhangsan",
    age:20,
    info:{
        address:"北京" // 需要深度监听
    },
    nums: [10,20,30]
}

observer(data)


//测试
// data.name = "Eeeee"
// data.age = 32

// data.x = '100' //新增属性，监听不到 -- Vue.set
// delete data.name  //删除属性，监听不到  -- Vue.delete
// console.log("DDDDD")

data.nums.push(4)

//Object.defineProperty()缺点：
/*
    1.深度监听，需要递归到底，一次性计算量大

    2. 无法监听新增属性/删除属性 （Vue.set Vue.delete)

    3. 无法原生监听数组，需要特殊处理
*/